package org.infodavid.common.services;

import java.util.List;

import javax.persistence.PersistenceException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.infodavid.common.dto.IDocumentCategoryListItem;
import org.infodavid.common.dto.IDocumentVersionListItem;
import org.infodavid.common.impl.services.validators.DefaultDocumentCategoryValidator;
import org.infodavid.common.impl.services.validators.DefaultDocumentVersionValidator;
import org.infodavid.common.model.IDocument;
import org.infodavid.common.model.IDocumentCategory;
import org.infodavid.common.model.IDocumentVersion;
import org.infodavid.common.model.ModelFactory;
import org.infodavid.common.model.behaviors.IApprovable.EApprovalStatus;
import org.infodavid.common.model.criteria.ICategoryCriteria;
import org.infodavid.common.model.criteria.IDocumentVersionCriteria;
import org.infodavid.common.reflect.InstantiationHelper;
import org.infodavid.common.services.exceptions.ServiceException;
import org.infodavid.common.services.validators.IValidator;

/**
 * The Class DocumentService.
 */
public abstract class DocumentService extends
    AbstractEntityService<IDocumentVersionListItem,IDocumentVersion,IDocumentVersionCriteria> {

	/** The singleton. */
	private static final DocumentService SINGLETON;

	/** The Constant log. */
	private static final Log LOGGER = LogFactory.getLog(DocumentService.class);

	static {
		try {
			SINGLETON = InstantiationHelper.getInstance().newInstance(DocumentService.class);
		}
		catch (final Exception e) {
			LOGGER.fatal("Can not instantiate the " + DocumentService.class.getName(), e);

			throw new Error(e);
		}
	}

	/**
	 * returns the singleton.
	 * @return <code>CityService</code>
	 */
	public static DocumentService getInstance() {
		return SINGLETON;
	}

	/** The category validator. */
	private IValidator<IDocumentCategory> categoryValidator = new DefaultDocumentCategoryValidator();

	/**
	 * Instantiates a new service.
	 */
	protected DocumentService() {
		super(IDocumentVersion.class, new DefaultDocumentVersionValidator(), ModelFactory.getInstance()
		    .getBuilder(IDocumentVersion.class));
	}

	/**
	 * Find last version by name.
	 * @param context the context
	 * @param value the value
	 * @return the i document version
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public abstract IDocumentVersion findLastVersionByName(IApplicationContext context, String value)
	    throws PersistenceException, ServiceException;

	/**
	 * Find by last version.
	 * @param context the context
	 * @param key the key
	 * @return the i document version
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public abstract IDocumentVersion findByLastVersion(IApplicationContext context, Long key)
	    throws PersistenceException, ServiceException;

	/**
	 * Find by last version by approval.
	 * @param context the context
	 * @param key the key
	 * @param status the status
	 * @return the i document version
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public abstract IDocumentVersion findByLastVersionByApproval(IApplicationContext context,
	    Long key, EApprovalStatus status) throws PersistenceException, ServiceException;

	/**
	 * Gets the document.
	 * @param context the context
	 * @param key the key
	 * @return the document
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public abstract IDocument getDocument(IApplicationContext context, long key)
	    throws PersistenceException, ServiceException;

	/**
	 * Find document by name.
	 * @param contextMock the context mock
	 * @param name the name
	 * @return the document
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public abstract IDocument findDocumentByName(IApplicationContext contextMock, String name)
	    throws PersistenceException, ServiceException;

	public abstract IDocumentCategory findCategoryByName(IApplicationContext context, String value)
	    throws PersistenceException, ServiceException;

	/**
	 * Adds the.
	 * @param context the context
	 * @param value the value
	 * @return the long
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public abstract long addCategory(IApplicationContext context, IDocumentCategory value)
	    throws PersistenceException, ServiceException;

	/**
	 * Find categories.
	 * @param context the context
	 * @param entities the entities
	 * @param criteria the criteria
	 * @return the long
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public abstract long findCategories(IApplicationContext context,
	    List<IDocumentCategoryListItem> entities, ICategoryCriteria criteria)
	    throws PersistenceException, ServiceException;

	/**
	 * Gets the category.
	 * @param context the context
	 * @param key the key
	 * @return the category
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public abstract IDocumentCategory getCategory(IApplicationContext context, long key)
	    throws PersistenceException, ServiceException;

	/**
	 * Gets the category validator.
	 * @return the validator
	 */
	public IValidator<IDocumentCategory> getCategoryValidator() {
		return categoryValidator;
	}

	/**
	 * Removes the category.
	 * @param context the context
	 * @param key the key
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public abstract void removeCategory(IApplicationContext context, long key)
	    throws PersistenceException, ServiceException;

	/**
	 * Sets the category validator.
	 * @param value the new validator
	 */
	public void setCategoryValidator(final IValidator<IDocumentCategory> value) {
		categoryValidator = value;
	}

	/**
	 * Update.
	 * @param context the context
	 * @param value the value
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public abstract void updateCategory(IApplicationContext context, IDocumentCategory value)
	    throws PersistenceException, ServiceException;
}
